package beanstao.util.setting;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;

import org.dom4j.Element;

import beanstao.util.exception.technical.util.reflect.FailToSetValueException;
import beanstao.util.log.ILog;
import beanstao.util.log.LogHelper;
import beanstao.util.reflect.InvokePrivateMethod;
import beanstao.util.reflect.Mirror;
import beanstao.util.xml.XDocument;

/**
 * 设置管理的抽象基类
 * 
 * @author beanstao@google.com 
 */
public class SettingManager implements ILog
{
	public final static String FILL_DATA_METHOD_NAME = "fillSettingData";

	protected SettingManager()
	{

	}

	private XDocument _SettingDocument = null;

	protected final SettingCollection _SettingCollection = new SettingCollection();

	/**
	 * 获取指下Key(不分大小写)的Setting(具体实现类)
	 * 
	 * @param key
	 * @return
	 */
	@SuppressWarnings({ "rawtypes" })
	public Setting getSetting(String key)
	{
		return _SettingCollection.get(key.toLowerCase());
	}

	public int getSettingCount()
	{
		return _SettingCollection.size();
	}

	@SuppressWarnings("rawtypes")
	public boolean initializes(Object... objects)
	{
		if (objects[0] instanceof XDocument)
			_SettingDocument = (XDocument) objects[0];
		HashMap<String, Element> classname$elementMap = this.getElementByClassMap(_SettingDocument);
		for (String classname : classname$elementMap.keySet())
		{
			// 第1步： 获取指定的类型 ==========================
			Mirror<?> mirror;
			Class<?> klass = null;
			try
			{
				klass = Class.forName(classname);
			}
			catch (ClassNotFoundException e1)
			{
				this.logWarn(classname + " 类型未发现。", e1);
				return false;
			}
			mirror = Mirror.me(klass);

			// 第2步： 获取指定对象的实例 ==========================
			Setting childSetting = null;
			try
			{
				childSetting = (Setting) mirror.born();
			}
			catch (Exception e)
			{
				this.logWarn(childSetting.toString() + " 获取指定对象的实例出错。", e);
				return false;
			}

			// 第3步： 调用fillSettingData方法 ====================
			try
			{
				this.filldata(classname$elementMap.get(classname), childSetting);
			}
			catch (Exception e)
			{
				this.logWarn(String.format("调用 fillSettingData 的 %s 相关方法出错。", classname), e);
				return false;
			}
			_SettingCollection.put(classname$elementMap.get(classname).attributeValue("name").toLowerCase(), childSetting);
		}
		return (null != _SettingDocument);
	}

	/**
	 * 从指定的Document中的约定的节点遍历获得所有定义的“设置”的类的全名
	 * 
	 * @param document
	 * @return
	 */
	protected HashMap<String, Element> getElementByClassMap(XDocument document)
	{
		HashMap<String, Element> classMap = new HashMap<String, Element>();
		List<?> nodes = document.getRootElement().selectNodes("//setting[@class]");
		for (Object object : nodes)
		{
			if (!(object instanceof Element))
				continue;
			Element element = (Element) object;
			String className = element.attributeValue("class");
			this.logDebug("启用Setting配置类:" + className);
			classMap.put(className, element);
		}
		return classMap;
	}

	/**
	 * 将指定的 Element 交给具体的 Setting 类的 filldata 方法实现该类的赋值。
	 * 
	 * @param element
	 * @param obj
	 * @throws NoSuchFieldException
	 * @throws FailToSetValueException
	 */
	@SuppressWarnings({ "rawtypes" })
	protected Setting filldata(Element element, Setting setting) throws FailToSetValueException, NoSuchFieldException
	{
		Method method = null;
		try
		{
			method = InvokePrivateMethod.getPrivateMethod(setting.getClass(), FILL_DATA_METHOD_NAME, Element.class);
		}
		catch (Exception e)
		{
			this.logWarn(String.format("获取类型方法%s时发生异常。", FILL_DATA_METHOD_NAME), e);
		}
		if (null == method)
			this.logWarn(String.format("无法找到类型中的%s方法。", FILL_DATA_METHOD_NAME));
		try
		{
			method.setAccessible(true);// 调用 private方法的关键一句话
			method.invoke(setting, element);
		}
		catch (Exception e)
		{
			this.logWarn("反射执行方法出错。方法名:" + method.getName() + "。被调用对象：" + setting.getClass().getSimpleName(), e);
		}
		return setting;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see beanstao.util.module.IManager#reLoad(org.dom4j.Document)
	 */
	public boolean reStart()
	{
		_SettingCollection.clear();
		try
		{
			this.initializes(_SettingDocument);
		}
		catch (Exception ex)
		{
			return false;
		}
		return true;
	}

	// =============

	@Override
	public void logDebug(Object message)
	{
		LogHelper.logDebug(this, message);
	}

	@Override
	public void logDebug(Object message, Throwable t)
	{
		LogHelper.logDebug(this, message, t);
	}

	@Override
	public void logError(Object message)
	{
		LogHelper.logError(this, message);
	}

	@Override
	public void logError(Object message, Throwable t)
	{
		LogHelper.logError(this, message, t);
	}

	@Override
	public void logInfo(Object message)
	{
		LogHelper.logInfo(this, message);
	}

	@Override
	public void logInfo(Object message, Throwable t)
	{
		LogHelper.logInfo(this, message, t);
	}

	@Override
	public void logWarn(Object message)
	{
		LogHelper.logWarn(this, message);
	}

	@Override
	public void logWarn(Object message, Throwable t)
	{
		LogHelper.logWarn(this, message, t);
	}

}
